package com.ruoyi.me.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDictData;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.exception.ProcessStopException;
import com.ruoyi.common.utils.*;
import com.ruoyi.common.utils.biz.ResultSaveModule;
import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.dm.mapper.DataCollectionMapper;
import com.ruoyi.me.mapper.DifferentAltitudeMapper;
import com.ruoyi.me.service.DifferentAltitudeService;
import com.ruoyi.system.service.ISysDictDataService;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Service
@Slf4j
public class DifferentAltitudeServiceImpl implements DifferentAltitudeService {

    @Resource
    DifferentAltitudeMapper differentAltitudeMapper;
    @Value("${python.me.altitude.path}")
    private String altitudePath;
    @Value("${python.me.altitude.name}")
    private String altitudeName;
    @Value("${python.me.altitude.iniPath}")
    private String iniPath;
    @Value("${python.me.altitude.jsonPath}")
    private String jsonPath;

    @Autowired
    private DataCollectionMapper dataCollectionMapper;

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @Scheduled(cron = "0 30 2  * * *")
    public  void schedule() {
        //每天2点半,统计数据. 密度数据 的 每月高度
        /**
         * {GRACEA:{hight:[]},
         *  time:[]
         * }
         */
        log.info("开始统计 密度卫星每月平均高度");
        List<String> allTables = dataCollectionMapper.selectAllTableNames("piesat_dgdq");
        List<String> tables = allTables.stream()
                .filter(name -> name.contains("swdata_obs_den_"))
                //swdata_obs_den_explorer9 数据太旧了,不参与
                .filter(name -> !name.contains("explorer9"))
                .collect(Collectors.toList());
        Set<Date> timeSet = new HashSet<>();
        Map<String,Map> sateMap = new TreeMap<>();
        for (String table : tables) {
            int num = 5;
            while (true) {
                try {
                    String sql = "select AVG(alt) as hight,date_trunc('month', time) as time from " + table + " group by date_trunc('month', time)";
                    List<SateMonthHightBO> hightBOS = jdbcTemplate.query(sql, new RowMapper<SateMonthHightBO>() {
                        @Override
                        public SateMonthHightBO mapRow(ResultSet rs, int rowNum) throws SQLException {
                            java.sql.Date time = rs.getDate("time");
                            float hight = rs.getFloat("hight") / 1000;
                            return new SateMonthHightBO(time, hight);
                        }
                    });
                    Map<Date, Float> timeMap = new HashMap<>();
                    for (SateMonthHightBO hightBO : hightBOS) {
                        timeMap.put(hightBO.getTime(), hightBO.getHight());
                    }
                    String sate = table.substring(table.lastIndexOf("_") + 1, table.length());
                    sateMap.put(sate, timeMap);
                    for (SateMonthHightBO hightBO : hightBOS) {
                        timeSet.add(hightBO.getTime());
                    }
                    //跳出
                    break;

                } catch (Exception e) {
                    log.error("查询高度异常", e);
                }
                num--;
                if (num < 0) {
                    //跳出
                    break;
                }
            }
        }
        //获取 时间范围,然后 获取rang
        Date maxdate = timeSet.stream().max(Date::compareTo).get();
        Date mindate = timeSet.stream().min(Date::compareTo).get();
        DateRange range = DateUtil.range(mindate, maxdate, DateField.MONTH);
        List<String> timeResList = new ArrayList<>();

        Map<String, Object> resMap = new HashMap<>();

        //code 转name
        List<SysDictData> satellites = sysDictDataService.listAllSatellite();
        Map<String, List<SysDictData>> nameCodeMap = satellites.stream().collect(Collectors.groupingBy(a ->a.getDictValue().toUpperCase()));

        for (DateTime dateTime : range) {
            timeResList.add(dateTime.toString("yyyy-MM"));
        }
        resMap.put("time",timeResList);

        for (String sate : sateMap.keySet()) {
            //卫星 编码 转名字
            List<SysDictData> sysDictData = nameCodeMap.get(sate.toUpperCase());
            String name = "";
            if (sysDictData != null) {
                name = sysDictData.get(0).getDictLabel();
            }else {
                name = sate.toUpperCase();
            }
            Map<Date, Float> datas = sateMap.get(sate);
            Map<String, List> resInner = new HashMap<>();
            List hightList = new ArrayList<>();
            //这个得重复创建
            DateRange rangeInner = DateUtil.range(mindate, maxdate, DateField.MONTH);
            for (DateTime dateTime : rangeInner) {
                hightList.add(datas.get(dateTime)==null?"null":datas.get(dateTime));
            }
            resInner.put("hight",hightList);
            resMap.put(name,resInner);
        }
        //替换旧的文件
        String json = jsonPath+"MODEL_EVALUATION_HEIGHT_STATISTICS"+".json";
        FileUtils.createJson(json, resMap);
    }


    @Override
    public AjaxResult testAdd(String path) {
        //进行文件信息添加
        try {
            List<Date> time = new ArrayList<>();
            String[] args = {"CHAMP","GOCE","GRACEFO","SWARMA","SWARMB","SWARMC","GRACEA","GRACEB"};
            List<String> sateList = Arrays.asList(args);
            Map<String, Object> maps = new HashMap<>();
            ObjectMapper mapper = new ObjectMapper();
            maps = mapper.readValue(new File(path), Map.class);
            for (String satellite : args) {
                Object o = maps.get(satellite);
                if (o == null){
                    continue;
                }
                time.add(DateUtils.convertString2Date("yyyy-MM",((Map)maps.get(satellite)).get("Start_time").toString().substring(0,7)));
                time.add(DateUtils.convertString2Date("yyyy-MM",((Map)maps.get(satellite)).get("End_time").toString().substring(0,7)));
            }
            //进行日期去重排序
            List<Date> listWithoutDuplicates = time.stream().distinct().collect(Collectors.toList());
            Collections.sort(listWithoutDuplicates, (a, b) -> a.compareTo(b));
            List<Date> dateList = new ArrayList<>();
            Date date = listWithoutDuplicates.get(0);
            while (!date.after(listWithoutDuplicates.get(listWithoutDuplicates.size()-1))){
                dateList.add(date);
                Calendar calendar = Calendar.getInstance();
                calendar.setTime(date);
                calendar.add(Calendar.MONTH, 1);
                date = calendar.getTime();
            }
            Map<String,Object> dataMap = new HashMap<>();
            //遍历每一个卫星下的数据对于缺失的数据设置为null
            List<String> tiList = new ArrayList<>();
            for (String satellite : sateList ) {
                Map<String, Object> mp = (Map<String, Object>) maps.get(satellite);
                List<String> timeList = (List<String>) mp.get("time");
                List<String> heList = (List<String>) mp.get("hight");
                Map<String, Object> timeH = new HashMap<>();
                Map<String,Object> sateMap = new HashMap<>();
                for (int i = 0; i<timeList.size();i++) {
                    timeH.put(timeList.get(i).substring(0,7),heList.get(i));
                }
                List<Object> hList = new ArrayList<>();
                //进行时间匹配
                for (Date date1 : dateList) {
                    String times = DateUtils.convertDate2String("yyyy-MM",date1);
                    if (timeH.containsKey(times)){
                        hList.add(timeH.get(times));
                    }else {
                        hList.add("null");
                    }
                    if (dateList.size()!=tiList.size()){
                        tiList.add(times);
                    }
                }
                Map<String, Object> timeMap = new HashMap<>();
//                sateMap.put("time",tiList);
                sateMap.put("hight",hList);
                dataMap.put(satellite, sateMap);
                //进行数据入库处理
                Date startDate = DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",((Map)maps.get(satellite)).get("Start_time").toString());
                Date endDate = DateUtils.convertString2Date("yyyy-MM-dd HH:mm:ss",((Map)maps.get(satellite)).get("End_time").toString());
//                differentAltitudeMapper.testAdd(SequenceBuilder.sequenceId(), satellite, startDate , endDate, JSON.toJSONString(dataMap), new Date(),Double.valueOf(((Map)maps.get(satellite)).get("averageHight")+""));
            }
            String json = jsonPath+"MODEL_EVALUATION_HEIGHT_STATISTICS"+".json";
            //生成json文件
            dataMap.put("time",tiList);
            FileUtils.createJson(json, dataMap);
            differentAltitudeMapper.testAdd(SequenceBuilder.sequenceId(), json, new Date());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public AjaxResult getSatelliteData() {



        //获取卫星数据
        Map<String, Object> map = differentAltitudeMapper.getSatelliteData();
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> resMap = null;
        try {
            resMap = mapper.readValue(new File(map.get("PATH").toString()), Map.class);
        } catch (IOException e) {
            e.printStackTrace();
        }
//        List<String> nameList = new ArrayList<>();
//        List<Map<String, Object>> tableList = new ArrayList<>();
//        Map<String, Object> lineChart = new HashMap<>();
//        for (Map<String, Object> map : list) {
            //添加所有卫星
//            nameList.add(map.get("SATELLITE")+"");
//            //添加表格数据
//            Map<String, Object> tableMap = new HashMap<>();
//            tableMap.put("spacecraftName",map.get("SATELLITE"));
//            tableMap.put("avgHeight",map.get("AVG_HEIGHT"));
//            tableMap.put("startTime",map.get("START_TIME"));
//            tableMap.put("endTime",map.get("END_TIME"));
//            tableMap.put("source","实测");
//            tableList.add(tableMap);
            //添加折线图数据
//            lineChart.putAll(JSON.parseObject(map.get("JSON_DATA")+"",Map.class));
//        }
//        Map<String, Object> resMap = new HashMap<>();
////        resMap.put("tableList",tableList);
//        resMap.put("nameList",nameList);
//        resMap.put("lineChart",lineChart);
        return AjaxResult.success("获取成功！",resMap);
    }

    @Override
    public AjaxResult getCalculateResult(Map<String, Object> map) throws ProcessStopException {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        String sseId = map.get("sseId")+"";
        sseId+=loginUser.getUsername();
        map.put("iniPath",iniPath);
        String json = jsonPath+map.get("startTime").toString().replaceAll("-","")+".json";
        //生成json文件
        FileUtils.createJson(json, map);
        List<String> commands = new ArrayList<>();
        commands.add("python");
        //给调用python 命令中加上参数（-u）代表-u代表不通过缓存，直接输出,或者python代码print 结束后执行刷新缓冲区操作sys.stdout.flush()
        commands.add("-u");
        commands.add(altitudePath+altitudeName);
        commands.add(json);
        commands.add(iniPath);
        System.out.println("python"+ " -u "+altitudePath+altitudeName+ " "+json + " " + iniPath);
        String results = ExecUtil.execPython(commands, sseId);
        //results = 【！！！！成功连接dmsql数据库！！！！！！！！参评卫星在轨运行共同时间段: {'Start_time': '2013-11-28 00:00:00', 'End_time': '2017-05-22 14:19:42'} ！！！！！！！！文件保存成功！！！！###/dgdq/tmp/modelAssess/different_heights_cal_density/Different_Heights_Eval_Result.txt###】
        if (results.contains("###")){
            System.out.println(results);
            results = results.split("###")[1];
        }
        if (results.equals("error")){
            SseEmitterUtils.sendMessage(sseId,"100");
            SseEmitterUtils.remove(sseId);
            return AjaxResult.warn("选择时间有误，请重新选择");
        }
//        String results = "C:\\Users\\zys\\Desktop\\Different_Heights_Eval_Result.txt";
        List<String> satelliteList = new ArrayList<>();
        for (String str : (List<String>)map.get("satellite")) {
            String[] arg = str.split("_");
            satelliteList.add(arg[arg.length-1]);
        }
        List<String> modelList = (List<String>) map.get("model");
        Map<String, Object> reMap = new HashMap<>();
        Map<String,Object> resMap = new HashMap<>();
        try {
            ObjectMapper mapper = new ObjectMapper();
            reMap = mapper.readValue(new File(results), Map.class);
            Map<String, Object> modelData = (Map<String, Object>) reMap.get("modelData");
            Map<String, Object> obsSimulate = new HashMap<>();
            Map<String, Object>  errorData = (Map<String, Object>) reMap.get("errorData");
//            List<Map<String, Object>>  tableList = (Map<String, Object>) reMap.get("errorData");
            Map<String, Object> error = new HashMap<>();
            String[] heads = {"satellite","model","absolute_error","relative_error","root_mean_square_error","corrCoee"};
            List<String> hList = Arrays.asList(heads);
            List<Map<String, Object>> headList = new ArrayList<>();
            String name = "";
            for (String  head : hList) {
                Map<String, Object> headMp = new HashMap<>();
                switch (head) {
                    case "satellite":
                        name = "卫星";
                        headMp.put(head,name);
                        break;
                    case "model":
                        name = "模型";
                        headMp.put(head,name);
                        break;
                    case "absolute_error":
                        name = "平均绝对误差";
                        headMp.put(head,name);
                        break;
                    case "relative_error":
                        name = "平均相对误差";
                        headMp.put(head,name);
                        break;
                    case "root_mean_square_error":
                        name = "均方根";
                        headMp.put(head,name);
                        break;
                    case "corrCoee":
                        name = "相关系数";
                        headMp.put(head,name);
                        break;
                }
                headList.add(headMp);
            }
            List<String> xList = new ArrayList<>();
            Map<String, Object> erroMap = new HashMap<>();
            List<Map<String, Object>> tableList = new ArrayList<>();
            Map<String, Object> height = (Map<String, Object>) reMap.get("height");
            for (String satellite : satelliteList) {
                //获取观测与模型模拟结果
                Map<String, Object> simulateMap = (Map<String, Object>) modelData.get(satellite+"_simu");
                simulateMap.put("obs", modelData.get(satellite));
                simulateMap.put("time", modelData.get(satellite+"_time"));
                obsSimulate.put(satellite, simulateMap);
                //获取不同高度下误差结果
                Map<String, Object> errorMap = new HashMap<>();
                Map<String, Object> absoluteMap = new HashMap<>();
                Map<String, Object> relativeMap = new HashMap<>();
                //拼装表格内容
                for (String model : modelList ) {
                    Map<String, Object> tableMap = new HashMap<>();
                    //获取每个模型的、绝对误差、相对误差、均方根误差
                    absoluteMap.put(model, errorData.get(satellite+"#"+model+"#absolute_error#result"));
                    relativeMap.put(model, errorData.get(satellite+"#"+model+"#relative_error#result"));
                    //拼装表格数据绝对误差、相对误差、均方根误差置信度区间
                    tableMap.put("satellite", height.get(satellite)+"km("+satellite+"卫星)");
                    tableMap.put("model", model);
                    tableMap.put("absolute_error", errorData.get(satellite+"#"+model+"#absolute_error#confidenceInterval"));
                    tableMap.put("relative_error", errorData.get(satellite+"#"+model+"#relative_error#confidenceInterval"));
                    tableMap.put("root_mean_square_error", errorData.get(satellite+"#"+model+"#root_mean_square_error#result"));
                    tableMap.put("corrCoee", errorData.get(satellite+"#"+model+"#corrCoee"));
                    tableList.add(tableMap);
                }
                errorMap.put("absolute_error",absoluteMap);
                errorMap.put("relative_error",relativeMap);
                errorMap.put("time", modelData.get(satellite+"_time"));
                error.put(satellite, errorMap);
                //拼装柱状图X轴
                xList.add(height.get(satellite)+"km("+satellite+"卫星)");
            }
            erroMap.put("X",xList);
            //拼装柱状图Y轴
            Map<String, Object> absoluteAver = new HashMap<>();
            Map<String, Object>  relativeAver = new HashMap<>();
            Map<String, Object>  meanAver = new HashMap<>();
            Map<String, Object>  corrCoee = new HashMap<>();
            for (String model : modelList ) {
                List<Object> absoluteList = new ArrayList<>();
                List<Object> relativeList = new ArrayList<>();
                List<Object> meanList = new ArrayList<>();
                List<Object> corrList = new ArrayList<>();
                for (String satellite : satelliteList) {
                    absoluteList.add(errorData.get(satellite+"#"+model+"#absolute_error#averageResult"));
                    relativeList.add(errorData.get(satellite+"#"+model+"#relative_error#averageResult"));
                    meanList.add(errorData.get(satellite+"#"+model+"#root_mean_square_error#result")+"");
                    corrList.add(errorData.get(satellite+"#"+model+"#corrCoee")+"");
                }
                absoluteAver.put(model, absoluteList);
                relativeAver.put(model, relativeList);
                meanAver.put(model, meanList);
                corrCoee.put(model, corrList);
            }
            erroMap.put("absolute_error", absoluteAver);
            erroMap.put("relative_error", relativeAver);
            erroMap.put("root_mean_square_error", meanAver);
            erroMap.put("corrCoee", corrCoee);
            //拼装表格内容
            resMap.put("obsSimulate", obsSimulate);
            resMap.put("error", error);
            resMap.put("errorData", erroMap);
            resMap.put("tableData", tableList);
            resMap.put("headList",headList);



            //拼装最优模型推荐内容
            Map<String, Object> bestMap = (Map<String, Object>) reMap.get("bestModel");
            StringBuilder stringBuilder = new StringBuilder();
            //"bestModel": {
            //		"average_absolute_error": "Jacchia71",
            //		"average_relative_error": "Jacchia71",
            //		"average_root_mean_square_error": "Jacchia71",
            //		"average_corrCoee": "JB2008"
            //	},



            resMap.put("bestModel",stringBuilder.toString());




            List<String> list = Stream.of(results).collect(Collectors.toList());
            resMap.put("resultData", JSONUtil.toJsonStr(list));
            resMap.put("module", ResultSaveModule.MODEL_ASSESS);
            resMap.put("submodule", ResultSaveModule.MODEL_ASSESS_ALT);
        } catch (Exception e) {
            e.printStackTrace();
        }
        SseEmitterUtils.sendMessage(sseId,"100");
        SseEmitterUtils.remove(sseId);
        return AjaxResult.success("获取成功",resMap);
//        //删除文件
//        DealDataUtils.deleteFile(json);
//        System.out.println(resultss);


    }

    @Override
    public SseEmitter push(String id, String flag) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        return SseEmitterUtils.connect(id+loginUser.getUsername(), flag);
    }


    @Data
    @AllArgsConstructor
    class SateMonthHightBO {
        private Date time;

        private Float hight;
    }
}
